package com.express.gateway.manage.auth;

import com.express.gateway.common.CommonCons;
import com.express.gateway.common.GatewayAttribute;
import com.express.gateway.common.ResultFormat;
import com.express.gateway.manage.enums.StatusCodeEnum;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.User;
import io.vertx.ext.web.RoutingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Base64;
import java.util.Objects;

import static com.express.gateway.manage.auth.RolesConstant.USER_NAME_KEY;

/**
 * 使用json进行相应操作的权限认证
 *
 * @author flower
 */
public class ClientStaticAuth implements Handler<RoutingContext> {
    private static final Logger LOG = LogManager.getLogger(ClientStaticAuth.class);
    public static final String AUTH_LOGIN_FAILED = "Basic realm=\"" + GatewayAttribute.FULL_NAME + "\"";
    public static final String AUTHORIZATION_KEY = "WWW-Authenticate";
    public static final String AUTHORIZATION = "Authorization";
    public static final String IS_AUTH = "isAuth";

    public static ClientStaticAuth create() {
        return new ClientStaticAuth();
    }

    @Override
    public void handle(RoutingContext rct) {
        String path = rct.request().path();
        if (UserAuthUtil.exclude(path)) {
            LOG.debug("path: {}", path);
            rct.next();
            return;
        }
        if (rct.session().get(AUTHORIZATION) != null) {
            User user = User.create(rct.session().get(AUTHORIZATION));
            rct.setUser(user);
            rct.next();
            return;
        }
        String auth = rct.request().getHeader(AUTHORIZATION);
        if (Objects.isNull(auth)) {
            LOG.error("request header auth info is empty!");
            UserAuthUtil.welcome(rct);
            // rct.response().putHeader(AUTHORIZATION_KEY, AUTH_LOGIN_FAILED).setStatusCode(401).end();
            return;
        }
        if (rct.session().get(IS_AUTH)) {
            LOG.error("request header is_auth is false!");
            rct.session().remove(IS_AUTH);
            UserAuthUtil.welcome(rct);
            //rct.response().putHeader(AUTHORIZATION_KEY, AUTH_LOGIN_FAILED).setStatusCode(401).end();
            return;
        }

        try {
            String decoded = new String(Base64.getDecoder().decode(auth.split(" ")[1]));
            verifyLoginUser(rct, decoded);
        } catch (Exception e) {
            LOG.error("user can't access, jwt is null!");
            rct.response().end(ResultFormat.format(StatusCodeEnum.C401, e));
        }
    }

    public static void verifyLoginUser(RoutingContext event, String decoded) {
        final String user;
        final String pass;
        int colonIdx = decoded.indexOf(":");
        if (colonIdx != -1) {
            user = decoded.substring(0, colonIdx);
            pass = decoded.substring(colonIdx + 1);
        } else {
            user = decoded;
            pass = null;
        }

        UserAuthUtil.auth(user, pass, event.vertx(), res -> {
            if (res.failed()) {
                event.response().end(ResultFormat.format(StatusCodeEnum.C500, res.cause()));
                return;
            }
            JsonObject u = res.result();
            if (Objects.isNull(u)) {
                // LOG.error("user can't access, token is null!");
                event.response().putHeader(AUTHORIZATION_KEY, AUTH_LOGIN_FAILED).setStatusCode(401).end();
                return;
            }

            u.put(USER_NAME_KEY, user);
            event.session().put(CommonCons.KEY_USER_NAME, user);
            event.session().put(IS_AUTH, true);
            event.session().put(AUTHORIZATION, u);
            event.setUser(User.create(u));
            event.next();
        });
    }
}
